package com.hmall.cart.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.cart.config.CartProperties;
import com.hmall.cart.domain.dto.CartFormDTO;
import com.hmall.cart.domain.po.Cart;
import com.hmall.cart.domain.vo.CartVO;
import com.hmall.cart.mapper.CartMapper;
import com.hmall.cart.service.ICartService;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.UserContext;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 购物车业务实现类
 * 继承ServiceImpl，实现ICartService接口
 * 处理购物车核心业务逻辑
 */
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

    // 商品服务Feign客户端，用于远程调用商品服务
    private final ItemClient itemClient;

    // 购物车配置属性，获取购物车最大数量限制
    private final CartProperties cartProperties;

    /**
     * 添加商品到购物车
     * @param cartFormDTO 商品表单DTO，包含包含商品id、商品标题、商品特点、商品价格、商品图片等信息
     */
    @Override
    public void addItem2Cart(CartFormDTO cartFormDTO) {

        // 发起添加商品到购物车的Http请求时，拦截器已经将用户ID存入了当前线程的ThreadLocal中
        // 1.获取当前登录用户ID（从线程上下文获取）
        Long userId = UserContext.getUser();

        // 2.检查商品是否已在购物车中
        if (checkItemExists(cartFormDTO.getItemId(), userId)) {
            // 2.1 已存在，调用Mapper方法增加商品数量（原子性更新）
            baseMapper.updateNum(cartFormDTO.getItemId(), userId);
            return;
        }

        // 2.2 不存在，检查购物车是否已满
        checkCartsFull(userId);

        // 3.新增购物车条目
        // 3.1 将DTO转换为PO实体
        Cart cart = BeanUtils.copyBean(cartFormDTO, Cart.class);
        // 3.2 设置用户ID
        cart.setUserId(userId);
        // 3.3 保存到数据库
        save(cart);
    }

    /**
     * 查询当前用户的购物车列表
     * @return 包含商品基本信息、当前价格、库存状态等实时信息
     */
    @Override
    public List<CartVO> queryMyCarts() {

        // 1.查询当前用户的购物车列表
        // 查cart表查出来的是PO而不是VO，所以后续需要转换
        List<Cart> carts = lambdaQuery()
                // 判断当前购物车所属用户与当前用户是不是同一个用户
                .eq(Cart::getUserId, UserContext.getUser())
                .list();

        // 空值处理
        if (CollUtils.isEmpty(carts)) {
            return CollUtils.emptyList();
        }

        // 2.将PO列表转换为VO列表
        List<CartVO> vos = BeanUtils.copyList(carts, CartVO.class);

        // 3.处理VO中的商品实时信息（价格、库存、状态）
        handleCartItems(vos);

        return vos;
    }

    /**
     * 根据商品ID集合删除购物车条目
     * @param itemIds 商品ID集合
     */
    @Override
    public void removeByItemIds(Collection<Long> itemIds) {
        // 1.构建删除条件：用户ID + 商品ID集合
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Cart::getUserId, UserContext.getUser())
                .in(Cart::getItemId, itemIds);

        // 2.批量删除购物车条目
        remove(queryWrapper);
    }


    /**
     * 检查商品是否已在购物车中
     * @param itemId 商品ID
     * @param userId 用户ID
     * @return 存在返回true，否则返回false
     */
    private boolean checkItemExists(Long itemId, Long userId) {
        // 查询商品是否存在
        // 先查询购物车所属用户是否对的上
        // 再查购物车中对应商品ID是否对的上
        Long count = lambdaQuery()
                .eq(Cart::getUserId, userId)
                .eq(Cart::getItemId, itemId)
                .count();

        return count > 0;
    }

    /**
     * 检查购物车是否已满
     * @param userId 用户ID
     * @throws BizIllegalException 购物车已满时抛出异常
     */
    private void checkCartsFull(Long userId) {

        // 查询当前用户购物车条目数量
        Long count = lambdaQuery()
                .eq(Cart::getUserId, userId)
                .count();

        // 校验是否超过最大数量限制
        if (count >= cartProperties.getMaxAmount()) {
            throw new BizIllegalException(
                    StrUtil.format("用户购物车商品不能超过{}个", cartProperties.getMaxAmount())
            );
        }
    }

    /**
     * 处理购物车中的商品信息，补充实时数据
     * 补充CartVO有而Cart没有的字段信息 --- newPrice、status、stock等
     * 购物车服务唯一远程调用商品服务的地方 --- 调用商品服务的 queryItemByIds() 方法
     * @param vos 购物车VO列表
     */
    private void handleCartItems(List<CartVO> vos) {

        // 1.提取商品ID集合
        Set<Long> itemIds = vos.stream()
                .map(CartVO::getItemId)
                .collect(Collectors.toSet());

        // 2.远程调用商品服务，批量查询商品信息
        List<ItemDTO> items = itemClient.queryItemByIds(itemIds);

        // 空值处理
        if (CollUtils.isEmpty(items)) {
            return;
        }

        // 3.将商品列表转换为Map（key:商品ID，value:商品DTO）
        Map<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));

        // 4.为每个购物车VO填充商品实时信息
        for (CartVO vo : vos) {
            ItemDTO item = itemMap.get(vo.getItemId());
            if (item == null) {
                continue; // 商品不存在（可能已删除），跳过
            }
            vo.setNewPrice(item.getPrice());    // 设置最新价格
            vo.setStatus(item.getStatus());     // 设置商品状态
            vo.setStock(item.getStock());       // 设置库存数量
        }
    }

}